module spi_slave_drdy #(
    parameter SPI_MODE  = 0,       // SPI模式: 0,1,2,3
    parameter MSB_FIRST = 1,       // 1: MSB first, 0: LSB first
    parameter DRDY_TIMEOUT   = 100      // DRDY超时周期数（可配置）
) (
    input  wire        clk,        // FPGA主时钟
    input  wire        rst_n,      // 复位信号 (低有效)
    
    // SPI物理接口
    input  wire        sck,        // SPI时钟
    input  wire        cs_n,       // 片选 (低有效)
    input  wire        mosi,       // 主机输出数据
    output wire        miso,       // 从机输出数据
    
    // 数据接口
    input  wire [7:0]  tx_byte,    // 待发送字节
    output reg  [7:0]  rx_byte,    // 接收到的字节
    output reg         rx_valid,   // 接收数据有效标志
    
    // DRDY接口 (仅用于发送方向)
    output reg         drdy,       // 发送数据准备好标志
    input  wire        start_xfer  // 开始传输标志
);

// --------------------------
// 信号同步与边沿检测（共享逻辑）
// --------------------------
reg sck_sync, cs_n_sync;       // SPI信号同步到clk域
reg sck_prev, cs_prev;         // 延迟寄存器（用于边沿检测）
reg mosi_sync;                // MOSI同步寄存器
// 同步SPI异步信号（避免亚稳态）
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sck_sync  <= 1'b0;
        cs_n_sync <= 1'b1;  // CS默认高有效（无效）
        mosi_sync <= 1'b0;
    end else begin
        sck_sync  <= sck;
        cs_n_sync <= cs_n;
        mosi_sync <= mosi;
    end
end

// 延迟寄存器（用于检测边沿）
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sck_prev <= 1'b0;
        cs_prev  <= 1'b1;
    end else begin
        sck_prev <= sck_sync;
        cs_prev  <= cs_n_sync;
    end
end

// 边沿检测信号（共享）
wire sck_rise      = sck_sync && !sck_prev;
wire sck_fall      = !sck_sync && sck_prev;
wire cs_active     = !cs_n_sync && cs_prev;    // CS从高到低（开始传输）
wire cs_inactive   = cs_n_sync && !cs_prev;    // CS从低到高（结束传输）

// SPI模式对应的采样/移位边沿（共享）
wire sample_edge   = (SPI_MODE == 0 || SPI_MODE == 2) ? sck_rise : sck_fall;  // 接收采样边沿
wire shift_edge    = (SPI_MODE == 0 || SPI_MODE == 2) ? sck_fall : sck_rise;  // 发送移位边沿

// --------------------------
// 接收状态机（内含bit_cnt，完全状态机管控）
// --------------------------
// 接收状态定义
localparam IDLE_RX      = 1'b0;  // 空闲（未接收）
localparam RECEIVING_RX = 1'b1;  // 接收中

reg rx_state;                   // 接收状态寄存器
reg [7:0] rx_shift_reg;         // 接收移位寄存器
reg [2:0] bit_cnt_rx;              // 位计数器（状态机内管控）

// 接收状态机逻辑，含bit_cnt完整控制
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        rx_state    <= IDLE_RX;
        rx_shift_reg <= 8'b0;
        rx_byte     <= 8'b0;
        rx_valid    <= 1'b0;
        bit_cnt_rx     <= 3'd7;  // 复位时初始化计数器
    end else begin
        case (rx_state)
            IDLE_RX: begin
                rx_valid <= 1'b0;
                // 当CS有效且检测到采样边沿时，开始接收
                if (cs_n_sync == 1'b0 && sample_edge) begin
                    rx_state <= RECEIVING_RX;
                    bit_cnt_rx  <= 3'd6;  // 新字节开始，从最高位计数
                    // 采样第1位数据
                    if (MSB_FIRST) begin
                        rx_shift_reg <= {rx_shift_reg[6:0], mosi_sync};  // MSB优先：左移，新位补最低位
                    end else begin
                        rx_shift_reg <= {mosi_sync, rx_shift_reg[7:1]};  // LSB优先：右移，新位补最高位
                    end
                end
            end
            
            RECEIVING_RX: begin
                // 持续采样数据（每采样边沿更新移位寄存器和bit_cnt）
                if (sample_edge) begin
                    if (MSB_FIRST) begin
                        rx_shift_reg <= {rx_shift_reg[6:0], mosi_sync};  // MSB优先：左移，新位补最低位
                    end else begin
                        rx_shift_reg <= {mosi_sync, rx_shift_reg[7:1]};  // LSB优先：右移，新位补最高位
                    end
                    
                    if (bit_cnt_rx == 3'd0) begin
                        // 完成1字节，锁存数据+置有效标志
                        rx_byte  <= MSB_FIRST ? {rx_shift_reg[6:0], mosi_sync} : {mosi_sync, rx_shift_reg[7:1]};
                        rx_shift_reg <= 'd0; // 清空移位寄存器
                        rx_valid <= 1'b1;
                        rx_state <= IDLE_RX;  // 回到空闲
                        bit_cnt_rx  <= 3'd7;     // 预复位，为下一字节准备
                    end else begin
                        bit_cnt_rx <= bit_cnt_rx - 1'b1;  // 未完成，继续计数
                    end
                end
                
                // 若CS无效，提前终止接收
                if (cs_inactive) begin
                    rx_state <= IDLE_RX;
                    bit_cnt_rx  <= 3'd7;  // 复位计数器
                end
            end
        endcase
    end
end

// --------------------------
// 发送状态机（负责MISO发送）
// --------------------------
// 发送状态定义
localparam IDLE_TX     = 2'b00;  // 空闲
localparam PREPARE_TX  = 2'b01;  // 准备发送（DRDY有效）
localparam SENDING_TX  = 2'b10;  // 发送中
localparam DONE_TX     = 2'b11;  // 发送完成（等待CS拉高）

reg [1:0] tx_state;             // 发送状态寄存器
reg [7:0] tx_shift_reg;         // 发送移位寄存器
reg miso_reg;                   // MISO输出寄存器
reg [11:0] timeout_cnt;         // 超时计数器（用于DRDY状态）
reg [2:0] bit_cnt_tx;              // 位计数器（0-7）

// 计算实际超时值（限制为12位最大值）
localparam MAX_TIMEOUT = 12'd4095;  // 12位计数器最大值
localparam ACTUAL_TIMEOUT = (DRDY_TIMEOUT > MAX_TIMEOUT) ? MAX_TIMEOUT : DRDY_TIMEOUT;


// 发送状态机逻辑（修正后）
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        tx_state    <= IDLE_TX;
        tx_shift_reg <= 8'b0;
        miso_reg    <= 1'b0;
        drdy        <= 1'b0;
        timeout_cnt <= 12'd0;
        bit_cnt_tx     <= 3'd7;    // 初始化位计数器
    end else begin
        case (tx_state)
            IDLE_TX: begin
                drdy <= 1'b0;
                timeout_cnt <= 12'd0;
                
                if (start_xfer) begin
                    tx_state <= PREPARE_TX;
                    drdy     <= 1'b1;  // 单周期DRDY脉冲
                end
            end
            
            PREPARE_TX: begin
                drdy <= 1'b0;  // 单周期后拉低
                timeout_cnt <= timeout_cnt + 1'b1;
                
                if (cs_active) begin  // CS拉低，开始发送
                    tx_shift_reg <= tx_byte;
                    tx_state <= SENDING_TX;
                    timeout_cnt <= 12'd0;
                    if(SPI_MODE==1)begin
                        bit_cnt_tx  <= 3'd7;    // 第一位未输出, 剩余8位
                    end
                    else begin
                        miso_reg <= MSB_FIRST ? tx_byte[7] : tx_byte[0];
                        bit_cnt_tx  <= 3'd6;    // 第一位已输出，剩余7位
                    end
                end else if (timeout_cnt >= ACTUAL_TIMEOUT) begin
                    tx_state <= IDLE_TX;
                    timeout_cnt <= 12'd0;
                end
            end
            
            SENDING_TX: begin
                if (shift_edge) begin
                    // 模式1特殊处理：第一次移位时输出第一位数据
                    if (SPI_MODE == 1 && bit_cnt_tx == 3'd7) begin
                        // 输出第一位数据（未移位）
                        miso_reg <= MSB_FIRST ? tx_shift_reg[7] : tx_shift_reg[0];
                        bit_cnt_tx <= 3'd6;  // 剩余7位
                    end else begin
                        // 正常移位并输出下一位（适用于所有模式的后续位）
                        if (MSB_FIRST) begin
                            miso_reg     <= tx_shift_reg[6];
                            tx_shift_reg <= {tx_shift_reg[6:0], 1'b0};
                        end else begin
                            miso_reg     <= tx_shift_reg[1];
                            tx_shift_reg <= {1'b0, tx_shift_reg[7:1]};
                        end
                        
                        if (bit_cnt_tx == 3'd0) begin
                            tx_state <= DONE_TX;  // 8位发送完成
                        end else begin
                            bit_cnt_tx <= bit_cnt_tx - 1'b1;
                        end
                    end
                end
                
                if (cs_inactive) begin
                    tx_state <= IDLE_TX;  // CS拉高，提前结束
                end
            end
            
            DONE_TX: begin
                if (cs_inactive) begin
                    tx_state <= IDLE_TX;  // 等待CS拉高
                end
            end
        endcase
    end
end

// --------------------------
// MISO三态控制
// --------------------------
assign miso = (cs_n_sync) ? 1'bz : miso_reg;  // CS无效时高阻，有效时输出miso_reg

endmodule